package com.chenyuxin.ilp.service.file.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chenyuxin.ilp.exception.BaseException;
import com.chenyuxin.ilp.mapper.file.FileFolderMistakeMapper;
import com.chenyuxin.ilp.mapper.file.FileMetaMistakeMapper;
import com.chenyuxin.ilp.mapper.user.UserStorageMapper;
import com.chenyuxin.ilp.model.constant.FileSuccessConstant;
import com.chenyuxin.ilp.model.dto.file.AddFileMistakeDto;
import com.chenyuxin.ilp.model.dto.file.AddFolderMistakeDto;
import com.chenyuxin.ilp.model.entity.file.FileFolderMistake;
import com.chenyuxin.ilp.model.entity.file.FileMeta;
import com.chenyuxin.ilp.model.entity.file.FileMetaMistake;
import com.chenyuxin.ilp.model.entity.user.UserStorage;
import com.chenyuxin.ilp.model.enums.exception.ExceptionEnums;
import com.chenyuxin.ilp.model.enums.exception.FileExceptionEnums;
import com.chenyuxin.ilp.model.enums.exception.UserExceptionEnums;
import com.chenyuxin.ilp.model.pojo.Result;
import com.chenyuxin.ilp.model.vo.file.FileMistakeVo;
import com.chenyuxin.ilp.model.vo.file.FolderMistakeVo;
import com.chenyuxin.ilp.service.file.FileMistakeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FileMistakeServiceImpl implements FileMistakeService {
    @Autowired
    private FileMetaMistakeMapper fileMetaMistakeMapper;
    @Autowired
    private FileFolderMistakeMapper fileFolderMistakeMapper;
    @Autowired
    private UserStorageMapper userStorageMapper;
    @Autowired
    private MinioServiceImpl minioService;
    @Value("${minio.bucket.files}")
    private String bucket;
    @Override
    public Result addMistakeFolder(AddFolderMistakeDto addFolderMistakeDto, String userId) {
        FileFolderMistake fileFolderMistake = new FileFolderMistake();
        fileFolderMistake.setFolderName(addFolderMistakeDto.getFolderName());
        fileFolderMistake.setUserId(userId);
        fileFolderMistake.setCreateTime(LocalDateTime.now());
        fileFolderMistakeMapper.insert(fileFolderMistake);
        return Result.ok(FileSuccessConstant.ADD_MISTAKE_FOLDER_SUCCESS,null);
    }
    @Transactional
    @Override
    public Result addMistakeFile(Long folderId, MultipartFile file, String userId) {
        String originalFilename = file.getOriginalFilename();
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        if(!extension.equals(".pdf")){
            throw new BaseException(FileExceptionEnums.MISTAKE_FILE_NOT_PDF);
        }
        // 判断是否存在同名文件
        Boolean exist = this.existFile(userId, folderId,originalFilename);
        if (exist){
            throw new BaseException(FileExceptionEnums.MISTAKE_FILE_EXIST);
        }
        //2 更新用户剩余存储空间
        double fileSize = file.getSize() / (1024.0 * 1024.0);
        UserStorage userStorage = userStorageMapper.selectById(userId);
        if(userStorage.getUsedSize()+fileSize>userStorage.getTotalSize()){
            throw new BaseException(UserExceptionEnums.STORAGE_FULL);
        }
        LambdaUpdateWrapper<UserStorage> storageWrapper = new LambdaUpdateWrapper<>();
        storageWrapper.eq(UserStorage::getId,userId)
                        .set(UserStorage::getUsedSize,userStorage.getUsedSize()+fileSize)
                        .set(UserStorage::getUpdateTime,LocalDateTime.now());
        userStorageMapper.update(storageWrapper);
        //3 存储错题文件到mysql
        FileMetaMistake fileMetaMistake = new FileMetaMistake();
        fileMetaMistake.setFolderId(folderId);
        fileMetaMistake.setFileName(originalFilename);
        fileMetaMistake.setFileSize(fileSize);
        fileMetaMistake.setUserId(userId);
        fileMetaMistake.setCreateTime(LocalDateTime.now());
        fileMetaMistakeMapper.insert(fileMetaMistake);
        //4 存储错题文件到minio
        File tempFile = null;
        try{
            tempFile = File.createTempFile("minio", extension);
            //上传的文件拷贝到临时文件
            file.transferTo(tempFile);
        }catch (Exception exception){
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        String absolutePath = tempFile.getAbsolutePath();
        String objectName = "/"+userId+"/mistake/"+folderId+"/"+fileMetaMistake.getId()+extension;
        Boolean upload = minioService.upload(absolutePath, bucket, objectName,extension);
        if(!upload){
            throw new BaseException(FileExceptionEnums.FILE_UPLOAD_ERROR);
        }
        if (tempFile.exists()) {
            tempFile.delete();
        }
        return Result.ok(FileSuccessConstant.ADD_MISTAKE_FILE_SUCCESS,null);
    }

    @Override
    public Result deleteMistakeFolder(Long folderId, String userId) {
        //1 判断是否有未删除的子文件
        LambdaQueryWrapper<FileMetaMistake> fileWrapper = new LambdaQueryWrapper<>();
        fileWrapper.eq(FileMetaMistake::getFolderId,folderId)
                .eq(FileMetaMistake::getUserId,userId);
        Long count = fileMetaMistakeMapper.selectCount(fileWrapper);
        if(count>0){
            throw new BaseException(FileExceptionEnums.MISTAKE_FOLDER_EXIST_FILE);
        }
        //2 删除文件夹
        LambdaQueryWrapper<FileFolderMistake> folderWrapper = new LambdaQueryWrapper<>();
        folderWrapper.eq(FileFolderMistake::getId,folderId)
                .eq(FileFolderMistake::getUserId,userId);
        fileFolderMistakeMapper.delete(folderWrapper);
        return Result.ok(FileSuccessConstant.DELETE_MISTAKE_FOLDER_SUCCESS,null);
    }
    @Transactional
    @Override
    public Result deleteMistakeFile(Long fileId, String userId) {
        LambdaQueryWrapper<FileMetaMistake> fileWrapper = new LambdaQueryWrapper<>();
        fileWrapper.eq(FileMetaMistake::getId,fileId)
                .eq(FileMetaMistake::getUserId,userId);
        FileMetaMistake fileMetaMistake = fileMetaMistakeMapper.selectOne(fileWrapper);
        int delete = fileMetaMistakeMapper.delete(fileWrapper);
        if(delete!=1){
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        LambdaUpdateWrapper<UserStorage> storageWrapper = new LambdaUpdateWrapper<>();
        storageWrapper.eq(UserStorage::getId,userId)
                .setSql("used_size = used_size - " + fileMetaMistake.getFileSize());
        userStorageMapper.update(storageWrapper);
        String fileName = fileMetaMistake.getFileName();
        String extension = fileName.substring(fileName.lastIndexOf("."));
        String objectName = "/"+userId+"/mistake/"+fileMetaMistake.getFolderId()+"/"+fileId+extension;
        Boolean minioDelete = minioService.delete(bucket, objectName);
        if(!minioDelete){
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        return Result.ok(FileSuccessConstant.DELETE_MISTAKE_FILE_SUCCESS,null);
    }
    // 预览错题文件
    @Override
    public Result previewMistakeFile(Long fileId, String userId) {
        LambdaQueryWrapper<FileMetaMistake> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileMetaMistake::getId,fileId)
                .eq(FileMetaMistake::getUserId,userId);
        FileMetaMistake fileMetaMistake = fileMetaMistakeMapper.selectOne(wrapper);
        if(fileMetaMistake==null){
            throw new BaseException(FileExceptionEnums.MISTAKE_FILE_NOT_EXIST);
        }
        String extension = fileMetaMistake.getFileName().substring(fileMetaMistake.getFileName().lastIndexOf("."));
        String fileObjectName = "/"+userId+"/mistake/"+fileMetaMistake.getFolderId()+"/"+fileId+extension;
        String previewUrl = minioService.getPreviewUrl(bucket, fileObjectName);
        return Result.ok(previewUrl);
    }
    // 下载错题文件
    @Override
    public ResponseEntity<byte[]> downloadMistakeFile(String userId, Long fileId) {
        LambdaQueryWrapper<FileMetaMistake> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileMetaMistake::getId,fileId)
                .eq(FileMetaMistake::getUserId,userId);
        FileMetaMistake fileMetaMistake = fileMetaMistakeMapper.selectOne(wrapper);
        if(fileMetaMistake==null){
            throw new BaseException(FileExceptionEnums.MISTAKE_FILE_NOT_EXIST);
        }
        String extension = fileMetaMistake.getFileName().substring(fileMetaMistake.getFileName().lastIndexOf("."));
        String objectName = "/"+userId+"/mistake/"+fileMetaMistake.getFolderId()+"/"+fileId+extension;
        byte[] fileByte = minioService.download(objectName);
        HttpHeaders headers = new HttpHeaders();
        try {
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileMetaMistake.getFileName(), StandardCharsets.UTF_8.toString()));
        } catch (UnsupportedEncodingException e) {
            log.error("封装ResponseEntity出现异常,objectName:{},errorMessage:{}",objectName,e.getMessage());
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        return new ResponseEntity<>(fileByte,headers, HttpStatus.OK);
    }
    // 查询用户错题文件夹
    @Override
    public Result selectMistakeFolder(String userId) {
        LambdaQueryWrapper<FileFolderMistake> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileFolderMistake::getUserId,userId);
        List<FileFolderMistake> fileFolderMistakes = fileFolderMistakeMapper.selectList(wrapper);
        List<FolderMistakeVo> folderMistakeVos = fileFolderMistakes.stream().map(fileFolderMistake -> {
            FolderMistakeVo folderMistakeVo = BeanUtil.copyProperties(fileFolderMistake, FolderMistakeVo.class);
            folderMistakeVo.setType(2);
            return folderMistakeVo;
        }).collect(Collectors.toList());
        return Result.ok(folderMistakeVos);
    }
    // 查询用户错题文件
    @Override
    public Result selectMistakeFile(Long folderId, String userId) {
        LambdaQueryWrapper<FileMetaMistake> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileMetaMistake::getFolderId,folderId)
                .eq(FileMetaMistake::getUserId, userId);
        List<FileMetaMistake> fileMetaMistakes = fileMetaMistakeMapper.selectList(wrapper);
        List<FileMistakeVo> fileMistakeVos = fileMetaMistakes.stream().map(fileMetaMistake -> {
            FileMistakeVo fileMistakeVo = BeanUtil.copyProperties(fileMetaMistake, FileMistakeVo.class);
            fileMistakeVo.setType(1);
            return fileMistakeVo;
        }).collect(Collectors.toList());
        return Result.ok(fileMistakeVos);
    }

    private Boolean existFile(String userId,Long folderId,String fileName){
        LambdaQueryWrapper<FileMetaMistake> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileMetaMistake::getFolderId,folderId)
                .eq(FileMetaMistake::getFileName,fileName)
                .eq(FileMetaMistake::getUserId,userId);
        FileMetaMistake fileMetaMistake = fileMetaMistakeMapper.selectOne(wrapper);
        if(fileMetaMistake==null){
            return false;
        }
        return true;
    }
}
